﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;

namespace ZSens.VMultiAPI
{
    class VMulti
    {
        #region vmulti.dll Imports
        [DllImport("vmulti.dll")]
        static extern bool vmulti_connect();
        [DllImport("vmulti.dll")]
        static extern bool vmulti_disconnect();
        [DllImport("vmulti.dll")]
        static extern bool vmulti_update_mouse(byte button, ushort x, ushort y, byte wheelPosition);
        [DllImport("vmulti.dll")]
        static extern bool vmulti_update_relative_mouse(byte button, ushort x, ushort y, byte wheelPosition);
        [DllImport("vmulti.dll")]
        static extern bool vmulti_update_digi(byte status, ushort x, ushort y);
        [DllImport("vmulti.dll")]
        static extern bool vmulti_update_joystick(ushort buttons, sbyte hat, sbyte x, sbyte y, sbyte rx, sbyte ry, sbyte throttle);
        [DllImport("vmulti.dll")]
        static extern bool vmulti_update_keyboard(byte shiftKeyFlags, byte[] keyCodes);
        #endregion

        internal class Joystick
        {
            internal class Button
            {
                internal Button(Joystick parent)
                {
                    _parent = parent;
                }
                private Joystick _parent;
                private bool _pressed = false;
                public bool Pressed
                {
                    get { return _pressed; }
                    set { _pressed = value; _parent.Update(); }
                }
            }
            
            private sbyte hat;
            private sbyte x;
            private sbyte y;
            private sbyte rx;
            private sbyte ry;
            private sbyte throttle;

            public sbyte HatPosition { get { return hat; } set { hat = value; Update(); } }
            public sbyte X { get { return x; } set { x = value; Update(); } }
            public sbyte Y { get { return y; } set { y = value; Update(); } }
            public sbyte RotateX { get { return rx; } set { rx = value; Update(); } }
            public sbyte RotateY { get { return ry; } set { ry = value; Update(); } }
            public sbyte Throttle { get { return throttle; } set { throttle = value; Update(); } }
            public Button[] Buttons { get; private set; }

            internal Joystick()
            {
                hat = x = y = rx = ry = 0;
                throttle = -127;
                Buttons = new Button[16];
                for (int i = 0; i < 16; ++i)
                    Buttons[i] = new Button(this);
            }
            public void Update()
            {
                ushort buttonStatus = 0;
                for (int i = 0; i < 16; ++i)
                    if (Buttons[i].Pressed)
                        buttonStatus |= (byte)(1 << i);
                if (!vmulti_update_joystick(buttonStatus, hat, x, y, rx, ry, throttle))
                    throw new Exception("Unable to update VMulti");
            }
        }


        static VMulti _instance;

        public Joystick JoyStick { get; private set; }

        private VMulti()
        {
            if (!vmulti_connect())
                throw new Exception("Cannot connect vmulti");
            JoyStick = new Joystick();
        }

        public static VMulti GetInstance()
        {
            if (_instance == null)
                _instance = new VMulti();
            return _instance;
        }
    }
}
